﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DO.DreamOnTrader.Quote;
using System.Data;
using System.Threading;
using System.Threading.Tasks;


namespace DO.DreamOnTrader.Trigger
{
	public delegate bool BasicTriggerEvaluatorByTick(Tick tick);

	public delegate bool BasicTriggerEvaluatorByKBar(KBar kbar);

	public class BasicTrigger : ITrigger
	{
		#region -----變數區

		/// <summary>
		/// 用來判別目前是己進場，己退場
		/// </summary>
		bool isInCase = false;

		readonly Product product = ProductSet.TX;
		readonly int Qty = 1;
		readonly ActionSet action = ActionSet.BUY;

		DataTable signalTable = new DataTable("signalTable");
		public DataTable SignalTable { get { return signalTable; } }

		BasicTriggerEvaluatorByTick InTriggerByTick;

		BasicTriggerEvaluatorByKBar InTriggerByKBar;

		BasicTriggerEvaluatorByTick OutTriggerByTick;

		BasicTriggerEvaluatorByKBar OutTriggerByKBar;

		ParameterizedThreadStart toInTriggerEventThread;

		ParameterizedThreadStart toOutTriggerEventThread;

		TaskFactory triggerTaskFactory = new TaskFactory();

		Task triggerTask = new Task(() => { });


		#endregion

		/// <summary>
		/// 建構式
		/// </summary>
		/// <param name="_Product">要交易的商品</param>
		/// <param name="_Qty">交易數量</param>
		/// <param name="_act">多空</param>
		public BasicTrigger(Product _Product, int _Qty, ActionSet _act)
		{
			product = _Product;
			Qty = _Qty;
			action = _act;

			signalTable.Columns.Add("進出場", typeof(string));
			signalTable.Columns.Add("商品", typeof(string));
			signalTable.Columns.Add("日期時間", typeof(DateTime));
			signalTable.Columns.Add("B/S", typeof(string));
			signalTable.Columns.Add("當時點數", typeof(float));
			signalTable.Columns.Add("委託價格", typeof(string));

			toInTriggerEventThread = new ParameterizedThreadStart(toInTriggerEvent);
			//toInTriggerEventThread.Priority = ThreadPriority.BelowNormal;
			toOutTriggerEventThread = new ParameterizedThreadStart(toOutTriggerEvent);
			//toOutTriggerEventThread.Priority = ThreadPriority.BelowNormal;

			triggerTask.Start();
		}

		/// <summary>
		/// 產生進場訊號
		/// </summary>
		/// <param name="_signal"></param>
		private void toInTriggerEvent(object _signal)
		{
			Signal signal = (Signal)_signal;

			DO.Common.Trace.InfoWrite("進場訊號", _signal.ToString());

			if (InTriggerEvent != null)
			{
				InTriggerEvent(signal);
			}

			DataRow dr = signalTable.NewRow();
			dr["進出場"] = "進";
			dr["商品"] = signal.mth + signal.product.ProductName;
			dr["日期時間"] = signal.dateTime;
			dr["B/S"] = signal.action.ToString();
			dr["當時點數"] = signal.actPrice;
			dr["委託價格"] = (float.IsNaN(signal.price)) ? "市價" : signal.price.ToString();
			lock (signalTable)
			{
				signalTable.Rows.Add(dr);
			}			
		}

		/// <summary>
		/// 產生出場訊號
		/// </summary>
		/// <param name="_signal"></param>
		private void toOutTriggerEvent(object _signal)
		{
			Signal signal = (Signal)_signal;

			DO.Common.Trace.InfoWrite("出場訊號", _signal.ToString());

			if (OutTriggerEvent != null)
			{
				OutTriggerEvent(signal);
			}

			DataRow dr = signalTable.NewRow();
			dr["進出場"] = "出";
			dr["商品"] = signal.mth + signal.product.ProductName;
			dr["日期時間"] = signal.dateTime;
			dr["B/S"] = signal.action.ToString();
			dr["當時點數"] = signal.actPrice;
			dr["委託價格"] = (float.IsNaN(signal.price)) ? "市價" : signal.price.ToString();

			lock (signalTable)
			{
				signalTable.Rows.Add(dr);
			}
		}


		#region =====設定進出場條件的邏輯

		/// <summary>
		/// 設定進場條件
		/// </summary>
		/// <param name="evt"></param>
		public void setInTrigger(BasicTriggerEvaluatorByTick evt)
		{
			InTriggerByTick = evt;
		}

		/// <summary>
		/// 設定進場條件
		/// </summary>
		/// <param name="evt"></param>
		public void setInTrigger(BasicTriggerEvaluatorByKBar evt)
		{
			InTriggerByKBar = evt;
		}

		/// <summary>
		/// 設定出場條件
		/// </summary>
		/// <param name="evt"></param>
		public void setOutTrigger(BasicTriggerEvaluatorByTick evt)
		{
			OutTriggerByTick = evt;
		}

		/// <summary>
		/// 設定出場條件
		/// </summary>
		/// <param name="evt"></param>
		public void setOutTrigger(BasicTriggerEvaluatorByKBar evt)
		{
			OutTriggerByKBar = evt;
		}

		#endregion

		/// <summary>
		/// 接收到TICK報價時
		/// </summary>
		/// <param name="tick"></param>
		private void takeQuote(Tick tick)
		{
			if (isInCase)
			{	//己進場時
				if (OutTriggerByTick(tick))
				{
					isInCase = false;

					//task
					//triggerTask = triggerTask.ContinueWith((PrevTask) =>
					//{
						toOutTriggerEvent(new Signal(product, tick.CloseMonth, Qty, ~action, tick.TradeTime, tick.Price));
					//});
				}
			}
			else
			{	//空手時
				if (InTriggerByTick(tick))
				{
					isInCase = true;

					//task
					//triggerTask = triggerTask.ContinueWith((PrevTask) =>
					//{
						toInTriggerEvent(new Signal(product, tick.CloseMonth, Qty, action, tick.TradeTime, tick.Price));
					//});
				}
			}
		}

		
		/// <summary>
		/// 接收到KBAR報價時
		/// </summary>
		/// <param name="kbar"></param>
		private void takeQuote(KBar kbar)
		{
			if (isInCase)
			{
				//己進場時
				if (OutTriggerByKBar(kbar))
				{
					isInCase = false;

					//task
					triggerTask = triggerTask.ContinueWith((PrevTask) =>
					{
						toOutTriggerEvent(new Signal(product, kbar.CloseMonth, Qty, ~action, kbar.Ktime, kbar.ClosePrice));
					});
				}
			}
			else
			{
				//空手時
				if (InTriggerByKBar(kbar))
				{
					isInCase = true;

					//task
					triggerTask = triggerTask.ContinueWith((PrevTask) =>
					{
						toInTriggerEvent(new Signal(product, kbar.CloseMonth, Qty, action, kbar.Ktime, kbar.ClosePrice));
					});
				}
			}
		}

		#region -----報價source 

		ITickBuilder tickSource;
		/// <summary>
		/// 設定ticks builder的來源
		/// </summary>
		public ITickBuilder TickSource
		{
			set
			{
				if (tickSource != null)
					tickSource.BuildingTick -= new BuildingTickEventHandler(takeQuote);
				tickSource = value;
				tickSource.BuildingTick += new BuildingTickEventHandler(takeQuote);
			}
			get { return tickSource; }
		}

		IKBarBuilder kBarSource;
		/// <summary>
		/// 設定kbar builder的來源
		/// </summary>
		public IKBarBuilder KBarSource
		{
			set
			{
				if (kBarSource != null)
					kBarSource.BuildingKBar -= new BuildingKBarEventHandler(takeQuote);
				kBarSource = value;
				kBarSource.BuildingKBar += new BuildingKBarEventHandler(takeQuote);
			}
			get { return kBarSource; }
		}

		#endregion


		#region ITrigger 成員

		public event TriggerHandler InTriggerEvent;

		public event TriggerHandler OutTriggerEvent;

		#endregion
	}
}
